package com.hjy.backend.dataManager.page;

import com.hjy.backend.dataManager.pageCache.PageCache;
import com.hjy.backend.utils.Parser;

import java.util.Arrays;

/**
 * 普通页操作类
 * 一个普通页面以一个 2 字节无符号数起始，表示这一页的空闲位置的偏移量。剩下的部分都是实际存储的数据。
 * 2个字节可以表示的偏移量有 2^16 ,大于 8K, 成立的
 * 对普通页的管理，基本都是围绕着对 FSO（Free Space Offset）进行的
 */
public class PageNormal {
    private static final short OF_FREE = 0;
    private static final short OF_DATA = 2; // 偏移数据占几个位置
    public static final int MAX_FREE_SPACE = PageCache.PAGE_SIZE - OF_DATA; // 最大存储大小

    /**
     * 初始化普通页, 返回数据
     *
     * @return
     */
    public static byte[] initRaw() {
        byte[] raw = new byte[PageCache.PAGE_SIZE];
        setFSO(raw, OF_DATA);
        return raw;
    }

    /**
     * 设置当前的偏移大小
     *
     * @param raw
     * @param ofData
     */
    private static void setFSO(byte[] raw, short ofData) {
        System.arraycopy(Parser.short2Byte(ofData), 0, raw, OF_FREE, OF_DATA);
    }

    /**
     * 获取pg的FSO(空闲空间偏移数)
     */
    public static short getFSO(Page pg) {
        return getFSO(pg.getData());
    }

    /**
     * 获取页面空闲空间偏移大小
     *
     * @param raw
     * @return
     */
    private static short getFSO(byte[] raw) {
        return Parser.parseShort(Arrays.copyOfRange(raw, 0, 2));
    }

    /**
     * 将 raw 插入page中，返回开始的插入位置
     *
     * @param pg
     * @param raw
     * @return
     */
    public static short insert(Page pg, byte[] raw) {
        pg.setDirty(true);
        short offset = getFSO(pg.getData());
        System.arraycopy(raw, 0, pg.getData(), offset, raw.length);
        setFSO(pg.getData(), (short)(offset + raw.length));
        return offset;
    }

    /**
     * 获取页面的空闲空间大小
     *
     * @param pg
     * @return
     */
    public static int getFreeSpace(Page pg) {
        return PageCache.PAGE_SIZE - (int)getFSO(pg.getData());
    }

    /**
     * 将raw插入pg中的offset位置(任一位置)，并将pg的offset设置为较大的offset
     *
     * @param pg
     * @param raw
     * @param offset
     */
    public static void recoverInsert(Page pg, byte[] raw, short offset) {
        pg.setDirty(true);
        System.arraycopy(raw, 0, pg.getData(), offset, raw.length);
        // 获得当前偏移大小
        short rawFSO = getFSO(pg.getData());
        if(rawFSO < offset + raw.length) {
            setFSO(pg.getData(), (short)(offset+raw.length));
        }
    }

    /**
     * 将raw插入pg中的offset位置，不更新 pageOffset
     *
     * @param pg
     * @param raw
     * @param offset
     */
    public static void recoverUpdate(Page pg, byte[] raw, short offset) {
        pg.setDirty(true);
        System.arraycopy(raw, 0, pg.getData(), offset, raw.length);
    }
}
